package com.lanxiao.cloud.modules.oauth.domain.service.impl;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.lanxiao.cloud.common.core.enums.StateEnum;
import com.lanxiao.cloud.common.core.error.OauthErrorType;
import com.lanxiao.cloud.common.core.exception.BusinessException;
import com.lanxiao.cloud.common.core.utils.DateUtils;
import com.lanxiao.cloud.common.redis.template.RedisTemplateUtils;
import com.lanxiao.cloud.modules.oauth.domain.model.UserDetails;
import com.lanxiao.cloud.modules.oauth.domain.service.ISecurityService;
import com.lanxiao.cloud.modules.oauth.infrastructure.constant.OauthRedisConstant;
import java.util.List;
import org.springframework.stereotype.Service;

/**
 * @author ：qiaoliang
 * @date ：2021-10-20
 */
@Service
public class SecurityServiceImpl implements ISecurityService {

  private final byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded();

  @Override
  public String token(UserDetails userDetails) {
    SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
    final String token = aes.encryptHex(userDetails.getId() + "_" +
        userDetails.getUuId() + "_" +
        DateUtils.getCurrentTimestamp());
    RedisTemplateUtils.hashsSet(OauthRedisConstant.OAUTH_TOKEN, userDetails.getId().toString(), userDetails,
        60*60*24);
    return token;
  }

  @Override
  public UserDetails decryptToken(String token) {

    SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
    String s = null;
    try{
      s = aes.decryptStr(token);
    }catch (Exception ignored){
      throw new BusinessException(OauthErrorType.TOKEN_ERROR);
    }
    BusinessException.isNull(s, OauthErrorType.TOKEN_ERROR);
    final String[] message = s.split("_");

    BusinessException.isFalse(message.length == 3, OauthErrorType.TOKEN_ERROR);

    final Object o = RedisTemplateUtils.hashGet(OauthRedisConstant.OAUTH_TOKEN, message[0]);
    BusinessException.isNull(o, OauthErrorType.TOKEN_ERROR);
    UserDetails userDetails = (UserDetails)o;

    BusinessException.isFalse(message[1].equals(userDetails.getUuId()), OauthErrorType.OTHEN_LOGIN_END_ERROR);

    BusinessException.isTrue(StateEnum.ERROR.equals(userDetails.getState()), OauthErrorType.OTHEN_LOGIN_OFFLINE_ERROR);

    return userDetails;
  }


  @Override
  public List<UserDetails> onLineUser() {
    return RedisTemplateUtils.hashValusAll(OauthRedisConstant.OAUTH_TOKEN);
  }

  @Override
  public UserDetails onLineUser(String id) {
    return RedisTemplateUtils.hashGet(OauthRedisConstant.OAUTH_TOKEN, id);
  }

}
